import { MemoryStorageFile } from '@blazity/nest-file-fastify';
import { showBuilderEntity } from '@libs/common/repository';
import { indexPaginateBuilder } from '@libs/common/repository';
import { readExcel } from '@libs/common/utils';
import { Inject, Injectable } from '@nestjs/common';
import { Dayjs, FormatDate } from '@shencom/utils-date';
import { Equal, In, Repository } from 'typeorm';

import { MemberService } from '../../dingding/member/member.service';
import { cols, ColType } from './constant';
import {
  CreatePerformanceDto,
  DeletePerformanceDto,
  FindPerformanceDto,
  IndexPerformanceDto,
  ShowPerformanceDto,
  UpdatePerformanceDto,
} from './dto/performance.dto';
import { Performance } from './entities/performance.entity';
import { ProviderKey } from './performance.providers';

@Injectable()
export class PerformanceService {
  constructor(private memberService: MemberService) {}
  @Inject(ProviderKey)
  private repository: Repository<Performance>;

  async index(dto: IndexPerformanceDto) {
    const res = await indexPaginateBuilder({
      dto,
      repository: this.repository,
    });
    return res;
  }

  show<D extends ShowPerformanceDto = ShowPerformanceDto>(dto: D) {
    return showBuilderEntity(this.repository, dto);
  }

  async find(dto: FindPerformanceDto): Promise<Performance[]> {
    if (dto.userId) {
      return this.repository.findBy({ userId: Equal(dto.userId) });
    } else if (dto.dingId) {
      return this.repository.findBy({ dingId: Equal(dto.dingId) });
    } else if (dto.name) {
      return this.repository.findBy({ name: Equal(dto.name) });
    }

    return [];
  }

  delete(dto: DeletePerformanceDto) {
    const { id, ids } = dto;
    if (id) {
      return this.repository.delete({ id: Equal(id) });
    } else if (ids) {
      return this.repository.delete({ id: In(ids) });
    }
    return;
  }

  update(dto: UpdatePerformanceDto) {
    // return this.repository.update(dto.id, dto);
  }

  create(dto: CreatePerformanceDto | CreatePerformanceDto[]) {
    // return this.repository.save(plainToInstance(Performance, dto));
  }

  async import(date: string, files: MemoryStorageFile[]) {
    const arr: ColType[] = [];
    for (const file of files) {
      const workbook = await readExcel(file.buffer);

      const worksheets = workbook.worksheets;

      worksheets.forEach((worksheet) => {
        const data = <ColType>{};
        cols.forEach((col) => {
          const cell = worksheet.getCell(
            col.cell.toLocaleUpperCase() + col.row,
          );
          if (typeof cell.value === 'object' && cell.value !== null) {
            data[col.prop] = (cell.value as any).result as never;
          } else {
            data[col.prop] = cell.value as never;
          }
        });
        arr.push(data);
      });
    }

    const logs: Performance[] = [];
    const errMessage: string[] = [];
    for (const item of arr) {
      const {
        attitude,
        quality,
        efficiency,
        teamwork,
        score,
        attendance,
        name,
      } = item;

      if (!name) {
        errMessage.push('姓名未找到');
        continue;
      }

      const users = await this.memberService.findByName(name);
      const user = users[0];

      if (!user || !user.userId || !user.dingUserId) {
        errMessage.push(`${name} 用户未找到`);
        continue;
      }

      if (
        !attitude ||
        !quality ||
        !efficiency ||
        !teamwork ||
        !score ||
        !attendance
      ) {
        errMessage.push(`${name} 分数未取到`);
      }

      let currentLog = await this.repository.findOneBy({
        name: Equal(name),
        date: Dayjs(date).toDate(),
      });

      if (!currentLog) {
        currentLog = new Performance();
        currentLog.date = Dayjs(date).toDate();
        currentLog.name = user.name;
        currentLog.dingId = user.dingUserId;
        currentLog.userId = user.userId;
        currentLog.score = score;
      }

      currentLog.attitude = attitude;
      currentLog.quality = quality;
      currentLog.efficiency = efficiency;
      currentLog.teamwork = teamwork;
      logs.push(currentLog);

      const subtract_month = Dayjs(
        FormatDate(
          Dayjs(date as string)
            .subtract(1, 'month')
            .valueOf(),
        ),
      ).toDate();

      let preLog = await this.repository.findOneBy({
        name: Equal(name),
        date: subtract_month,
      });

      if (!preLog) {
        preLog = new Performance();
        preLog.date = subtract_month;
        preLog.name = user.name;
        preLog.dingId = user.dingUserId;
        preLog.userId = user.userId;
        preLog.attendance = attendance;
        logs.push(preLog);
      } else if (!preLog.attendance) {
        preLog.attendance = attendance;
        logs.push(preLog);
      }
    }

    await this.repository.save(logs);

    return {
      data: logs.length,
      errMessage,
    };
  }

  export() {
    // TODO
  }

  switch(id: string, status: boolean) {
    // status 需要在 entity 中定义, 如果没有不需要这个接口
    // return this.repository.update({ id }, { status });
  }
}
